from datetime import datetime

import numpy as nm
import scipy.sparse as sp


# 从全量偏好矩阵里，基于用户的度计算出稀疏增强图
# 主要就是统计出度数在中位数以下的项目和用户结点
# 把它们对应行/列里，非零的值变成指定小数参数
# 这样就等于增加了稀疏结点的交互记录，同时不影响本来的记录
def sparse_graph_augment(num_of_item, num_of_user, liked_graph):
    # 统计用户和项目的度，即用户看过的项目，和项目被看过的用户数量
    item_degree_vector = nm.zeros([num_of_item])
    user_degree_vector = nm.zeros([num_of_user])

    # 求每个项目的度，存在对应向量里
    for item_id in range(num_of_item):
        item_degree_vector[item_id] = liked_graph[item_id, :].sum()

    # 求每个用户的度，存在对应向量里
    for user_id in range(num_of_user):
        user_degree_vector[user_id] = liked_graph[:, user_id].sum()

    # 这里计算下项目的度的中位数
    # 然后把低于中位数（不含中位数）的项目id记录下来
    # 存进item_ids_under_middle
    item_ids_under_middle = []
    item_degree_middle = nm.median(item_degree_vector)
    for item_id in range(num_of_item):
        if item_degree_vector[item_id] < item_degree_middle:
            item_ids_under_middle.append(item_id)
    # 同理计算下用户的度的中位数
    # 然后把低于中位数（不含中位数）的用户id记录下来
    # 存进user_ids_under_middle
    user_ids_under_middle = []
    user_degree_middle = nm.median(user_degree_vector)
    for user_id in range(num_of_user):
        if user_degree_vector[user_id] < user_degree_middle:
            user_ids_under_middle.append(user_id)
    # 对liked_graph进行遍历
    # 如果行id属于item_ids_under_middle，则该行的值里，0值变成参数D
    # 如果列id属于user_ids_under_middle，则该列的值里，0值变成参数D
    # 得到的结果存在一个新矩阵里，sparse_liked_graph
    D = 0.7
    sparse_liked_graph = liked_graph.copy()
    for item_id in range(num_of_item):
        if item_id not in item_ids_under_middle:
            for user_id in range(num_of_user):
                if sparse_liked_graph[item_id, user_id] == 0:
                    sparse_liked_graph[item_id][user_id] = D
    for user_id in range(num_of_user):
        if user_id not in user_ids_under_middle:
            for item_id in range(num_of_item):
                if sparse_liked_graph[item_id, user_id] == 0:
                    sparse_liked_graph[item_id][user_id] = D

    sparse_liked_graph_nozero_count = nm.count_nonzero(sparse_liked_graph)
    print('sparse_liked_graph非0元素：', sparse_liked_graph_nozero_count)

    return sparse_liked_graph


# 接收稀疏矩阵格式的输入
def sparse_matrix_augment(liked_matrix):
    start_time = datetime.now()
    print(datetime.now(), ": 开始sparse_matrix_augment")
    inter_matrix = liked_matrix.copy()
    if not sp.isspmatrix_csr(inter_matrix):
        inter_matrix = inter_matrix.tocsr()
    # print(datetime.now(), ": sparse_matrix_augment: 转换csr结束")
    # 统计用户和项目的度，即用户看过的项目，和项目被看过的用户数量
    num_of_user = inter_matrix.shape[0]
    num_of_item = inter_matrix.shape[1]
    user_degree_vector = nm.zeros([num_of_user])
    item_degree_vector = nm.zeros([num_of_item])

    # 求每个用户的度，存在对应向量里
    for index in range(num_of_user):
        user_degree_vector[index] = inter_matrix.indptr[index+1] - inter_matrix.indptr[index]
    # print(datetime.now(), ": sparse_matrix_augment: 求user度结束")
    # 求每个项目的度，存在对应向量里
    for index in range(num_of_item):
        item_degree_vector[inter_matrix.indices[index]] += 1
    # print(datetime.now(), ": sparse_matrix_augment: 求item度结束")

    # 这里计算下项目的度的中位数
    # 然后把低于中位数（不含中位数）的项目id记录下来
    # 存进item_ids_under_middle
    item_ids_under_middle = []
    item_degree_middle = nm.median(item_degree_vector)
    for item_id in range(num_of_item):
        if item_degree_vector[item_id] < item_degree_middle:
            item_ids_under_middle.append(item_id)
    # 同理计算下用户的度的中位数
    # 然后把低于中位数（不含中位数）的用户id记录下来
    # 存进user_ids_under_middle
    user_ids_under_middle = []
    user_degree_middle = nm.median(user_degree_vector)
    for user_id in range(num_of_user):
        if user_degree_vector[user_id] < user_degree_middle:
            user_ids_under_middle.append(user_id)
    # print(datetime.now(), ": sparse_matrix_augment: 记录中位数结束")

    # 对inter_matrix进行遍历
    # 如果行id属于item_ids_under_middle，则该行的值里，0值变成参数D
    # 如果列id属于user_ids_under_middle，则该列的值里，0值变成参数D
    # 得到的结果存在一个新矩阵里，sparse_liked_graph
    D = 0.7
    inter_matrix = inter_matrix.tolil()
    # print(datetime.now(), ": sparse_matrix_augment: 转换lil结束")
    for item_id in range(num_of_item):
        if item_id in item_ids_under_middle:
            for user_id in range(num_of_user):
                if inter_matrix[user_id, item_id] == 0:
                    inter_matrix[user_id, item_id] = D
    # print(datetime.now(), ": sparse_matrix_augment: item方向增强结束")
    for user_id in range(num_of_user):
        if user_id in user_ids_under_middle:
            for item_id in range(num_of_item):
                if inter_matrix[user_id, item_id] == 0:
                    inter_matrix[user_id, item_id] = D
    # print(datetime.now(), ": sparse_matrix_augment: user方向增强结束")
    sparse_liked_graph_nonzero_count = inter_matrix.count_nonzero()
    print('sparse_matrix_augment非0元素：', sparse_liked_graph_nonzero_count)

    print(datetime.now(), ": sparse_matrix_augment: 全部结束")
    all_time = (datetime.now() - start_time).seconds
    print("sparse_matrix_augment耗时:", all_time)
    return inter_matrix

